﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace WayneGameSolution.Communicate.Tcp
{

    public class TcpServerSideLink : ServerSideLink, IServerSideLink
    {

        private SocketAsyncEventArgs ReceiveCargo;
        private SocketAsyncEventArgs SendCargo;
        private LinkedList<byte[]> ReceiveQueue = new LinkedList<byte[]>();
        private LinkedList<byte[]> SendQueue = new LinkedList<byte[]>();
        Socket _socket;
        byte[] _proveHead;
        public TcpServerSideLink(System.Net.Sockets.Socket socket, string proveString, int timeout)
        {
            ReceiveCargo=new SocketAsyncEventArgs();
            ReceiveCargo.Completed +=new EventHandler<SocketAsyncEventArgs>(ReceiveCargo_Completed);
            
            ReceiveCargo.SetBuffer (new byte[4096],0,4096);

            SendCargo = new SocketAsyncEventArgs ();
            SendCargo.Completed +=new EventHandler<SocketAsyncEventArgs>(SendCargo_Completed);
            SendCargo.SetBuffer (new byte[4096],0,4096);

            _socket.ReceiveAsync (new SocketAsyncEventArgs ());          
            _proveHead = System.Text.Encoding.UTF8.GetBytes(proveString);
            LastDataTime = DateTime.Now;
            TimeoutSecond = timeout;           


        }



        void  ReceiveCargo_Completed(object sender, SocketAsyncEventArgs e)
        {
            
            SocketError se =e.SocketError ;
            var length = e.BytesTransferred;
            if (se != SocketError.Success)
            {
                this.Close();
                return;
            }
            else
            {
                if (length != 0)
                {
                    var tbuffer = e.Buffer;
                    byte[] bs = new byte[length];

                    Array.Copy(tbuffer, e.Offset, bs, 0, length);
                    ReceiveQueue.AddLast(bs);
                    AfterReceive();
                    _socket.ReceiveAsync(e);
                }
                else 
                {
                    Close();
                }
            }

        }

        void SendCargo_Completed(object sender, SocketAsyncEventArgs e)
        {

            if (e.SocketError == SocketError.Success)
            {
                PackSent(_socket, e);
                if (SendQueue.Count > 0)
                {
                    InternalSendpackFromQueue();

                }
                else 
                {
                    _Sending = false;
                }
            }
            else
            {
                Close();
            }
        }

        private void AfterReceive()
        {
            if (IsLinkProved)
                BuildPack();
            else
                ProveLink();

        }

        private void ProveLink()
        {
            bool proved = true;
            var firstv = ReceiveQueue.FrontCutNodesFromNodeLists(_proveHead.Length);
            if (firstv.Length >= _proveHead.Length)
            {
                for (var i = 0; i < _proveHead.Length; i++)
                {
                    proved = firstv[i] == _proveHead[i];
                    if (!proved)
                    {
                        Close();
                    }
                }
            }
            else
                proved = false;

            IsLinkProved = proved;

        }
        private readonly byte[] packEnd = new byte[] { 0, 255, 127 };
        private const int headlength = 12;
        /// <summary>
        /// 建立包 
        /// 包格式:
        /// 长度 int32    
        /// 临时编号  int32      
        /// 包类型 Int32 
        /// 内容byte[] 结束byte[]packEnd
        /// </summary>
        private void BuildPack()
        {

            var lengthbytes = ReceiveQueue.PeekNodesFromNodeLists(4);
            if (lengthbytes.Length < 4) return;

            //包的最小大小为12+结尾
            var length = BitConverter.ToInt32(lengthbytes, 0);
            if (length < headlength + packEnd.Length) { Close(); return; };

            if (!ReceiveQueue.CheckHaveEnoughItems(length))
            {
                return;

            }
            var head = ReceiveQueue.FrontCutNodesFromNodeLists(headlength);
            var receivedData = ReceiveQueue.FrontCutNodesFromNodeLists(length - headlength);
            var tail = ReceiveQueue.FrontCutNodesFromNodeLists(packEnd.Length);
            var tmpid = BitConverter.ToInt32(head, 4);
            var flag = BitConverter.ToInt32(head, 8);
            if (receivedData.Length > 0)
            {
                //  包的结束必须为指定字节
                var tstart = receivedData.Length - 3;
                var isChecked = packEnd.Select(
                        (value, i) =>
                        {
                            return value == tail[i];
                        }
                    ).Aggregate(true, (s, n) => s = s && n); ;
                if (!isChecked) { Close(); return; }

                //ToDo Build LinkPack

                var p = PackCodec.ToDataPack(Cryptography, receivedData, flag, tmpid);
                PackReceived(p);
            }


        }




        public override void Close()
        {
            
            LinkClosing(this, null);
            _socket.Close(2);
            LinkClosed(this, null);
        }

        //private object _ReceivePackFromQueueSyncRoot = new object();


        public override void SendPack(IEnumerable<WayneGameSolution.Packs.IDataPack> packs)
        {
            SendPack(packs.ToArray());
        }
        private Boolean _Sending = false;
        public override void SendPack(params WayneGameSolution.Packs.IDataPack[] packs)
        {
            
            packs.ForEach
                (
                    (p, i) =>
                    {
                        p.TrackId = PackIndex;
                        this.SendQueue .AddLast(this.PackCodec.ToBytes(this.Cryptography, p));
                    }                        
                );


         
            if (!_Sending)
            {
                if (SendQueue.Count > 0)
                {
                    _Sending = true;
                    InternalSendpackFromQueue();
                        
                }

            }
        
            

            
        }

        void InternalSendpackFromQueue()
        {
            var np = this.SendQueue.First();
            this.SendQueue.RemoveFirst();
            SendCargo.SetBuffer(np, 0, np.Length);
            _socket.SendAsync(SendCargo);
        }
        
        



        public override event PackReceivedEventHandler PackReceived;

        public override event EventHandler PackSent;

        public override event EventHandler LinkClosing;

        public override event EventHandler LinkClosed;
    }





    //public class TcpServerSideLink_20 : ServerSideLink, IServerSideLink
    //{

    //    Socket _socket;
    //    byte[] _proveHead;
    //    public TcpServerSideLink_20(System.Net.Sockets.Socket socket, string proveString, int timeout)
    //    {
    //        _socket = socket;
    //        _proveHead = System.Text.Encoding.UTF8.GetBytes(proveString);
    //        LastDataTime = DateTime.Now;
    //        TimeoutSecond = timeout;

    //        var buffer = new byte[4096];
    //        _socket.BeginReceive
    //            (
    //              buffer, 0, buffer.Length,
    //              SocketFlags.None,
    //                Receiving,
    //             buffer
    //             );


    //    }
    //    private LinkedList<byte[]> ReceiveQueue = new LinkedList<byte[]>();
    //    private LinkedList<byte[]> SendQueue = new LinkedList<byte[]>();

    //    private void Receiving(IAsyncResult ar)
    //    {
    //        var skt = ar.AsyncState as Socket;
    //        SocketError se;
    //        var length = skt.EndReceive(ar, out se);
    //        if (se != SocketError.Success)
    //        {
    //            this.Close();
    //            return;
    //        }
    //        else
    //        {
    //            var tbuffer = ar.AsyncState as byte[];
    //            byte[] bs = new byte[length];
    //            Array.Copy(tbuffer, bs, length);
    //            ReceiveQueue.AddLast(bs);
    //            AfterReceive();
    //            skt.BeginReceive(tbuffer, 0, tbuffer.Length, SocketFlags.None, Receiving, tbuffer);
    //        }

    //    }
    //    private void AfterReceive()
    //    {
    //        if (IsLinkProved)
    //            BuildPack();
    //        else
    //            ProveLink();

    //    }

    //    private void ProveLink()
    //    {
    //        bool proved = true;
    //        var firstv = ReceiveQueue.FrontCutNodesFromNodeLists(_proveHead.Length);
    //        if (firstv.Length >= _proveHead.Length)
    //        {
    //            for (var i = 0; i < _proveHead.Length; i++)
    //            {
    //                proved = firstv[i] == _proveHead[i];
    //                if (!proved)
    //                {
    //                    Close();
    //                }
    //            }
    //        }
    //        else
    //            proved = false;

    //        IsLinkProved = proved;

    //    }
    //    private readonly byte[] packEnd = new byte[] { 0, 255, 127 };
    //    private const int headlength = 12;
    //    /// <summary>
    //    /// 建立包 
    //    /// 包格式:
    //    /// 长度 int32    
    //    /// 临时编号  int32      
    //    /// 包类型 Int32 
    //    /// 内容byte[] 结束byte[]packEnd
    //    /// </summary>
    //    private void BuildPack()
    //    {

    //        var lengthbytes = ReceiveQueue.PeekNodesFromNodeLists(4);
    //        if (lengthbytes.Length < 4) return;

    //        //包的最小大小为12+结尾
    //        var length = BitConverter.ToInt32(lengthbytes, 0);
    //        if (length < headlength + packEnd.Length) { Close(); return; };

    //        if (!ReceiveQueue.CheckHaveEnoughItems(length))
    //        {
    //            return;

    //        }
    //        var head = ReceiveQueue.FrontCutNodesFromNodeLists(headlength);
    //        var receivedData = ReceiveQueue.FrontCutNodesFromNodeLists(length - headlength);
    //        var tail = ReceiveQueue.FrontCutNodesFromNodeLists(packEnd.Length);
    //        var tmpid = BitConverter.ToInt32(head, 4);
    //        var flag = BitConverter.ToInt32(head, 8);
    //        if (receivedData.Length > 0)
    //        {
    //            //  包的结束必须为指定字节
    //            var tstart = receivedData.Length - 3;
    //            var isChecked = packEnd.Select(
    //                    (value, i) =>
    //                    {
    //                        return value == tail[i];
    //                    }
    //                ).Aggregate(true, (s, n) => s = s && n); ;
    //            if (!isChecked) { Close(); return; }

    //            //ToDo Build LinkPack

    //            var p = PackCodec.ToDataPack(Cryptography, receivedData, flag, tmpid);
    //            PackReceived(p);
    //        }


    //    }




    //    public override void Close()
    //    {
    //        LinkClosing(this, null);
    //        LinkClosed(this, null);
    //    }

    //    private object _ReceivePackFromQueueSyncRoot = new object();


    //    public override void SendPack(IEnumerable<WayneGameSolution.Packs.IDataPack> packs)
    //    {
    //        SendPack(packs.ToArray());
    //    }

    //    public override void SendPack(params WayneGameSolution.Packs.IDataPack[] packs)
    //    {
    //        //PackIndex

         
    //    }



    //    public override event PackReceivedEventHandler PackReceived;

    //    public override event EventHandler PackSent;

    //    public override event EventHandler LinkClosing;

    //    public override event EventHandler LinkClosed;
    //}

}
